/************************************************************************
 * The code is owned by mainframer.cn and Shang Tao
 * Without aproval of mainframer.cn and Shang Tao, remove the copyright
 * infomation is regarded invassion of proprietary copyright
 ***********************************************************************/
package com.mr.qa.action;

import java.util.Date;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import org.hibernate.Transaction;

import com.mr.qa.GlobalConfigs;
import com.mr.qa.UserSession;
import com.mr.qa.UserSessionUtil;
import com.mr.qa.bo.Message;
import com.mr.qa.bo.User;
import com.mr.qa.dao.impl.MessageDAO;
import com.mr.qa.dao.impl.UserDAO;
import com.mr.qa.exception.QaException;
import com.mr.qa.form.MessageForm;
import com.mr.qa.util.ActionHelper;
import com.mr.qa.util.DateUtil;
import com.mr.qa.util.HibernateSessionFactory;

public class MessageAction extends BaseAction {

    private static final Log log = LogFactory.getLog(MessageAction.class);
    public static int MAX_MESSAGES = GlobalConfigs.MAX_MESSAGES;
    private static final String ALL_NAME = "all";
    private static final String dateFormat = "yyyy-MM-dd";
    public ActionForward doAction(ActionMapping mapping, ActionForm form,
			HttpServletRequest request, HttpServletResponse response) throws Exception
    {
        ActionMessages errors = new ActionMessages();
        ActionMessages messages = new ActionMessages();
        UserSession us = UserSessionUtil.getUserSession(request);
        String action = this.getAction(request);
        MessageForm messageForm = (MessageForm)form;
        int page = messageForm.getPage();
        if(page == 0)page = 1;
        ActionForward af = null;
        if(us == null)
        {
            errors.add("relogin", new ActionMessage("login.required"));
            String forwardPath = "";
            //tomorrow to do
            if("add".equals(action))
            {
                Integer toUserId = messageForm.getToUserId();            
                String title = messageForm.getTitle();
                if(title == null)title = "";
                String content = messageForm.getContent();
                if(content == null)content = "";
                forwardPath = "/user.mrqa?action=viewuserbyother&id="+toUserId+"&openMsgDiv=true&title="+title+"&content="+content;
            }
            else
            {
                forwardPath = "/msg.mrqa?"+ActionHelper.getQueryString(request);
            }
            request.setAttribute(GlobalConfigs.ORIGINAL_URL,forwardPath);
            action = "relogin";
        }
        else
        {
            if("gotlist".equals(action))
            {
                Set list = gotList(new Integer(page), us.getUserId());
                
                request.setAttribute("gotmessages",list);
            }
            else if("sentlist".equals(action))
            {
                Set list = sentList(new Integer(page), us.getUserId());
                request.setAttribute("sentmessages",list);
            }
            else if("view".equals(action))
            {
                    Integer id = messageForm.getId();
                    Message message = getMessage(id);
                    if("0".equals(message.getState()) && "0".equals(message.getType()))
                        updateState(id, us.getUserId());
                    request.setAttribute("message",message);
                    if("1".equals(message.getType())) //sent
                    {
                        action = "views";
                    }
            }
            else if("add".equals(action))
            {
                String toUserLoginName = messageForm.getToUserLoginName();
                boolean hasRight = true;
                if(ALL_NAME.equals(toUserLoginName)) 
                {
                    if("0".equals(us.getType())) {
                        hasRight = false;
                    }
                }
                if(hasRight)
                {
                    String title = messageForm.getTitle();
                    String content = messageForm.getContent();
                    Integer toUserId = messageForm.getToUserId();
                    Date date = new Date();
                    String result = "";
                    if(toUserId != null)
                        result = add(title, content, date, us.getUserId(),toUserId,toUserLoginName);
                    else if(toUserId == null && toUserLoginName.length() > 0 && toUserLoginName.indexOf(",") < 0)
                        result = add(title, content, date, us.getUserId(),toUserId,toUserLoginName);
                    else if(toUserId == null && toUserLoginName.length() > 0 && toUserLoginName.indexOf(",") > 0)
                    {
                        String[] toUserLoginNames = toUserLoginName.split(",");
                        result = add(title, content, date, us.getUserId(), toUserLoginNames);
                    }
                    boolean isSent = false;
                    if("0".equals(result)) 
                    {
                        messages.add("",new ActionMessage("shortmessage.sent"));
                        isSent = true;
                    }
                    else if("2".equals(result)) 
                    {
                        errors.add("",new ActionMessage("nouser","nouser"));
                        action = "preadd";
                    }
                    else
                    {
                        messages.add("",new ActionMessage("invalidToUsers.sent",result));
                        isSent = true;
                    }
                    if(isSent)
                    { 
                        af = mapping.findForward(action);
                        String path = af.getPath();
                        String fromScreen = request.getParameter("from");
                        if("view".equals(fromScreen)) 
                        {
                            path = path.replace("!?","gotlist");
                        }
                        else if("views".equals(fromScreen)) 
                        {
                            path = path.replace("!?","sentlist");
                        }
                        else //from user's center viewed by others 
                        {
                            af = mapping.findForward("viewOtherUser");
                            path = af.getPath();
                            path = path.replace("!?1",fromScreen);
                            path = path.replace("!?2",""+toUserId);
                        }
                        af = new ActionForward(path);
                        af.setRedirect(true);
                    }
                }
                else {//has no right
                    action = "relogin";
                    errors.add("",new ActionMessage("nouser","nouser"));
                }
            }
            else if("delete".equals(action))
            {
                Integer id = messageForm.getId();
                //can not delete other's message
                Message message = delete(id,us.getUserId());
                //String from = request.getParameter("from");
                if("0".equals(message.getType()))
                {
                    String path = mapping.findForward(action).getPath().replace("!?","gotlist");
                    af = new ActionForward(path);
                    af.setRedirect(true);
                }
                else if("1".equals(message.getType()))
                {
                    String path = mapping.findForward(action).getPath().replace("!?","sentlist");
                    af = new ActionForward(path);
                    af.setRedirect(true);
                }
            }
            else if("preadd".equals(action)){
            	String name = null;
            	if(messageForm.getToUserLoginName() != null){
            		name = new String(messageForm.getToUserLoginName().getBytes("ISO-8859-1"),"UTF-8");
            	}
            	request.setAttribute("toUserLoginName", name);
            }
            else if("search".equals(action)){
            	String fromUser = messageForm.getFromUserLoginName();
            	String toUser = messageForm.getToUserLoginName();
            	String strFromDate = messageForm.getFromDate();
            	String strToDate = messageForm.getToDate();
            	
            	Date fromDate = null;
            	if(strFromDate != null && strFromDate.length() > 0){
            		fromDate = DateUtil.StringToDate(strFromDate, dateFormat);
            	}
            	Date toDate = null;
            	if(strToDate != null && strToDate.length() > 0){
            		toDate = DateUtil.StringToDate(strToDate, dateFormat);
            	}
            	int pageSize = messageForm.getPageSize();
            	if(pageSize == 0){
            		pageSize = 30;
            	}
            	List list = this.findMessages(fromUser, toUser, fromDate, toDate, "0", messageForm.getPage(), pageSize);
            	request.setAttribute("messageList", list);
            	request.setAttribute("page", ""+page);
            	request.setAttribute("pageSize", ""+pageSize);
            	
            	Long recordSize = findMessagesCount(fromUser, toUser, fromDate, toDate, "0");
            	request.setAttribute("resultSize", ""+recordSize);
            }
        }
        if(errors.size() > 0)           
            saveErrors(request.getSession(), errors);
        if(messages.size() > 0)
            saveMessages(request.getSession(), messages);
        if(af != null)
            return af;
        else
            return mapping.findForward(action);
    }
	
	
	public Message getMessage(Integer id) throws QaException
        {
	    Transaction tx = null;
	    Message message = null;
            try
            {
                tx = HibernateSessionFactory.getSession().beginTransaction();	    
		MessageDAO messageDAO = new MessageDAO();
		message = messageDAO.findById(id);
                tx.commit();
	    }catch(Exception re) {
	        if(tx != null)tx.rollback();
	        throw new QaException(re);
	    } finally {
	        HibernateSessionFactory.closeSession();                        
	    }
            return message;
	}
	
	private String add(String title, String content, Date date, 
        Integer fromUserId,Integer toUserId,String toUserLoginName) throws QaException
        {
		MessageDAO messageDAO = new MessageDAO();
		UserDAO userDAO = new UserDAO();
		Transaction tx = null;
                String result = "0";
		try {
			tx = HibernateSessionFactory.getSession().beginTransaction();
                        User toUser = null;
                        if(this.ALL_NAME.equals(toUserLoginName))
                        {
                            int count = userDAO.countAllUsers();
                            userDAO.setPage(1,count);
                            List users = userDAO.getList();
                            if(users.size() > 0)
                            {
                                User fromUser = userDAO.findById(fromUserId);
                                //toUser is null, to modify Message.xml and add column toUserLoginName
                                insertFromMessage(title,content,date,fromUser,fromUser.getLoginName(),
                                toUser,toUserLoginName,messageDAO);
                                insertToMessage(title,content,date,fromUser,users,messageDAO);
                            }
                        }
                        else
                        {
                            if(toUserId != null) 
                            {
                                toUser = userDAO.findById(toUserId);
                            }
                            else
                            {
                                List users = userDAO.findByLoginName(toUserLoginName);
                                if(users.size() > 0)
                                {
                                    toUser = (User)users.get(0);
                                }
                            }
                            if(toUser != null) 
                            {
                                User from = userDAO.findById(fromUserId);
                                sendMessage(title,content,date,from,toUser,messageDAO);
                            }
                            else
                                result = "2";
                        }
		        tx.commit();
		     }
                     catch(Exception re) {
		         if(tx != null)tx.rollback();
		         throw new QaException(re);
		     } finally {
		         HibernateSessionFactory.closeSession();                        
		     }
                     return result;
	}
    //toUserLoginName may be "all"
    public String add1(String title, String content, Date date, Integer fromUserId
    , String fromUserLoginName,Integer toUserId,String toUserLoginName) throws QaException
    {
            MessageDAO messageDAO = new MessageDAO();
            UserDAO userDAO = new UserDAO();
            Transaction tx = null;
            String result = "0";
            try {
                    tx = HibernateSessionFactory.getSession().beginTransaction();
                    User toUser = null;
                    toUser = userDAO.findById(toUserId);
                    if(toUserId !=null && toUserId > 0)
                    {
                        User from = userDAO.findById(fromUserId);
                        sendMessage(title,content,date,from,toUser,messageDAO);
                    }
                    else 
                    {
                      result = "2";  
                    }
                    tx.commit();
                 }
                 catch(Exception re) {
                     if(tx != null)tx.rollback();
                     throw new QaException(re);
                 } finally {
                     HibernateSessionFactory.closeSession();                        
                 }
                 return result;
    }

    public String add(String title, String content, Date date, Integer fromUserId,
    String[] toUserLoginNames) throws QaException
    {
            if(fromUserId == null)return "0";
            if(title == null || title.length() == 0)return "0";
            if(toUserLoginNames == null || toUserLoginNames.length == 0)return "0";
            MessageDAO messageDAO = new MessageDAO();
            UserDAO userDAO = new UserDAO();
            Transaction tx = null;
            String result = "0";
            String invalidToUsers = "";
            try {
                    tx = HibernateSessionFactory.getSession().beginTransaction();
                    User from = userDAO.findById(fromUserId);
                    String toUserLoginName = null;
                    User to;
                    for(int i=0;i<toUserLoginNames.length;i++)
                    {
                        toUserLoginName = toUserLoginNames[i];
                        if(toUserLoginName == null || toUserLoginName.length() == 0)continue;
                        List users = userDAO.findByLoginName(toUserLoginName);
                        if(users.size() > 0)
                        {
                           to = (User)users.get(0);
                           sendMessage(title,content,date,from,to,messageDAO);
                        }
                        else 
                        {
                            invalidToUsers += (invalidToUsers.length() >0)?(","+toUserLoginName):toUserLoginName;    
                        }
                    }
                    tx.commit();
                 }
                 catch(Exception re)
                 {
                     if(tx != null)tx.rollback();
                     throw new QaException(re);
                 } 
                 finally 
                 {
                     HibernateSessionFactory.closeSession();                        
                 }
                 if(invalidToUsers.length() > 0)result = invalidToUsers;
                 return result;
    }

    private void insertFromMessage(String title,String content,Date date,User from
    ,String fromUserLoginName,User to,String toUserLoginName,MessageDAO messageDAO) 
    {
        Message message = new Message();
        message.setTitle(title);
        message.setContent(content);
        message.setPostDate(date);
        message.setMrIaskUserByFromUserId(from);
        message.setMrIaskUserByToUserId(to);
        message.setFromUserLoginName(fromUserLoginName);
        message.setToUserLoginName(toUserLoginName);
        message.setState("0");
        message.setType("1");
        messageDAO.save(message);
    }

    private void insertToMessage(String title,String content,Date date,User from,
    String fromUserLoginName,User to,String toUserLoginName,MessageDAO messageDAO) 
    {
        Message toMessage = new Message();
        toMessage.setTitle(title);
        toMessage.setContent(content);
        toMessage.setPostDate(date);
        toMessage.setMrIaskUserByFromUserId(from);
        toMessage.setMrIaskUserByToUserId(to);
        toMessage.setFromUserLoginName(fromUserLoginName);
        toMessage.setToUserLoginName(toUserLoginName);
        toMessage.setState("0");
        toMessage.setType("0");
        messageDAO.save(toMessage);
    }

    //sent to multi users
    private void insertToMessage(String title,String content,Date date,User from,List<User> users,MessageDAO messageDAO) 
    {
        for(User toUser:users) 
        {
            //log.info(toUser);;
            insertToMessage(title,content,date,from,from.getLoginName(),toUser,toUser.getLoginName(),messageDAO);
        }
    }

    //
    //one from and one to, from and to can not be null
    private void sendMessage(String title,String content,Date date,User from,User to,MessageDAO messageDAO) 
    {
        insertFromMessage(title,content,date,from,from.getLoginName(),to,to.getLoginName(),messageDAO);
        insertToMessage(title,content,date,from,from.getLoginName(),to,to.getLoginName(),messageDAO);
        /*
        Message message = new Message();
        message.setTitle(title);
        message.setContent(content);
        message.setPostDate(date);
        message.setMrIaskUserByFromUserId(from);
        message.setMrIaskUserByToUserId(to);
        message.setState("0");
        message.setType("0");
        messageDAO.save(message);
        //2008.11.22
        Message toMessage = new Message();
        toMessage.setTitle(title);
        toMessage.setContent(content);
        toMessage.setPostDate(date);
        toMessage.setMrIaskUserByFromUserId(from);
        toMessage.setMrIaskUserByToUserId(to);
        toMessage.setState("0");
        toMessage.setType("1");
        messageDAO.save(toMessage);
        */
    }
	
	private void updateState(Integer id, Integer uId) throws QaException
        {
            Transaction tx = null;
            try
            {
                MessageDAO messageDAO = new MessageDAO();                
                tx = HibernateSessionFactory.getSession().beginTransaction();
                Message message = messageDAO.findById(id);
                if(message.getMrIaskUserByToUserId().getId().equals(uId))
		message.setState("1");
		messageDAO.update(message);
		tx.commit();
            }
            catch(Exception re) 
            {
                if(tx != null)tx.rollback();
                throw new QaException(re);
            } 
            finally
            {
                HibernateSessionFactory.closeSession();                        
            }
	}
	
	/**
         * delete a message
         * @param id message id
         * @param ownerId the owner of the message
         * @return
         * @throws QaException
         */
	public Message delete(Integer id, Integer ownerId) throws QaException
        {
            //boolean result = true;
            Transaction tx = null;
            try 
            {
                MessageDAO messageDAO = new MessageDAO();                
                tx = HibernateSessionFactory.getSession().beginTransaction();
                Message message = messageDAO.findById(id);
                //sent by the user whose user id is userId
                boolean hasRightToDelete = false;
                /*
                log.info("type="+message.getType());
                log.info("user="+ownerId);
                log.info("message from ="+message.getMrIaskUserByFromUserId().getId());
                log.info("message to ="+message.getMrIaskUserByToUserId().getId());
                log.info("if from="+(message.getMrIaskUserByFromUserId().getId().equals(ownerId))+"");
                log.info("if to="+(message.getMrIaskUserByToUserId().getId().equals(ownerId))+"");
                */
                if("1".equals(message.getType()) && message.getMrIaskUserByFromUserId().getId().equals(ownerId))
                {
                    hasRightToDelete = true;
                }
                else if("0".equals(message.getType()) && message.getMrIaskUserByToUserId().getId().equals(ownerId)) 
                {
                    hasRightToDelete = true;
                }
                if(hasRightToDelete)
                {
                    messageDAO.delete(message);
                }
                else
                {
                   //has no right to delete the message
                   log.warn("User:"+ownerId+" want to delete other's message:"+id);
                   throw new QaException("User has no right to delete other's message");
                }
               tx.commit();
               return message;
            }
            catch(Exception re)
            {
                if(tx != null)tx.rollback();
                throw new QaException(re);
            }
            finally
            {
                HibernateSessionFactory.closeSession();                        
            }
	}
	/**
         * messages to user
         * @param pageNo
         * @param toUserId
         * @return
         */
	public Set gotList(Integer pageNo, Integer toUserId) throws QaException
        {
            Set list = null;
	    Transaction tx = null;
	    try
            {
		UserDAO userDAO = new UserDAO();
	        MessageDAO messageDAO = new MessageDAO();
	        //messageDAO.setPage(pageNo, new Integer(30));
                tx = HibernateSessionFactory.getSession().beginTransaction();
		User user = userDAO.findById(toUserId);
		//use query to and state = 
                //list = messageDAO.findByProperty("mrIaskUserByToUserId.id", user.getId());
                list = user.getReceivedMessages();
                int count = list.size();
	        if(count > this.MAX_MESSAGES) {
	            //delete
	            Object[] messages = list.toArray();
	            Message message = null;
	            for(int i=this.MAX_MESSAGES;i<count;i++) {
	                message = (Message)messages[i];
	                list.remove(message);
	                messageDAO.delete(message);
	            }
	        }
                //log.info("received messages:"+list.size());
                tx.commit();
	    }catch(Exception re)
            {
	        if(tx != null)tx.rollback();
	        throw new QaException(re);
	    } finally
            {
	        HibernateSessionFactory.closeSession();                        
	    }
            return list;
	}
        /**
         * messages from user
         * @param page
         * @param toUserId
         * @return
         */
        public Set sentList(Integer page, Integer toUserId) throws QaException
        {
            Set list = null;
            Transaction tx = null;
            try
            {
                UserDAO userDAO = new UserDAO();
                MessageDAO messageDAO = new MessageDAO();
                //messageDAO.setPage(page, new Integer(30));
                tx = HibernateSessionFactory.getSession().beginTransaction();
                User user = userDAO.findById(toUserId);
                //list = messageDAO.findByProperty("mrIaskUserByFromUserId.id", user.getId());
                list = user.getSentMessages();
                int count = list.size();
                if(count > this.MAX_MESSAGES) {
                    Object[] messages = list.toArray();    
                    //delete
                    Message message = null;
                    for(int i=this.MAX_MESSAGES;i<count;i++) {
                        message = (Message)messages[i];
                        list.remove(message);
                        messageDAO.delete(message);
                    }
                }
                //log.info("sentmessages:"+list.size())
                tx.commit();
            }catch(Exception re)
            {
                if(tx != null)tx.rollback();
                throw new QaException(re);
            } finally
            {
                HibernateSessionFactory.closeSession();                        
            }
            return list;
        }

        
        private List findMessages(String fromUser, String toUser, Date fromDate, Date toDate, String type, int page, int recordCount) throws QaException{
        	List list = null;
        	Transaction tx = null;
        	try{
        		MessageDAO msgDAO = new MessageDAO();
        		tx = HibernateSessionFactory.getSession().beginTransaction();
        		msgDAO.setPage(page, recordCount);
        		list = msgDAO.findMessages(fromUser, toUser, fromDate, toDate, type);
        		tx.commit();
        	}catch(Exception e){
        		if(tx != null)tx.rollback();
                throw new QaException(e);
        	}finally
            {
                HibernateSessionFactory.closeSession();                        
            }
        	return list;
        }
        
        private Long findMessagesCount(String fromUser, String toUser, Date fromDate, Date toDate, String type) throws QaException{
        	Long result = null;
        	Transaction tx = null;
        	try{
        		MessageDAO msgDAO = new MessageDAO();
        		tx = HibernateSessionFactory.getSession().beginTransaction();
        		result = msgDAO.findMessagesCount(fromUser, toUser, fromDate, toDate, type);
        		tx.commit();
        	}catch(Exception e){
        		if(tx != null)tx.rollback();
                throw new QaException(e);
        	}finally
            {
                HibernateSessionFactory.closeSession();                        
            }
        	return result;
        }
}
